package wicketcool;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wicketcool.common.configuration.WicketCoolConfiguration;
import wicketcool.model.*;
import wicketcool.model.method.WCLMethod;
import wicketcool.model.method.WCLReturnStatement;
import wicketcool.model.types.WCLClassType;
import wicketcool.model.types.WCLInterfaceType;
import wicketcool.model.types.WCLNormalType;
import wicketcool.model.value.WCLClassValue;
import wicketcool.model.value.WCLNormalValue;
import wicketcool.model.value.WCLStringValue;
import wicketcool.plugins.Plugin;

import java.util.List;

/**
 * User: rabbit
 * Date: Jul 18, 2009
 */
@Component("domain")
public class DomainPlugin implements Plugin {

    @Autowired
    private JavaClassGenerator generator;

    public void run(List<String> arguments, WicketCoolConfiguration configuration) {

        if (arguments.isEmpty()) {
            System.out.println("Type 'wcl domain help' for more information");
            return;
        }

        if (arguments.get(0).equals("create")) {

            if (arguments.size() == 1) {
                System.out.println("Can't create entity. Please provide the name");
                return;
            }

            createDomainClass(arguments, configuration);
            createDaoInterface(arguments, configuration);
            createDaoClass(arguments, configuration);
            createServiceInterface(arguments, configuration);
        }
    }

    private void createDaoInterface(List<String> arguments, WicketCoolConfiguration configuration) {
        String packageName = configuration.getPackageName();
        String daoInterfaceName = arguments.get(1) + "DAO";
        String entityName = arguments.get(1);

        System.out.println("Creating DAO interface: " + daoInterfaceName + ".java");

        WCLInterface daoInterface = generator.initInterface(daoInterfaceName, packageName + ".domain.dao");

        daoInterface.addImport(new WCLImport(packageName + ".domain.entities." + entityName, false, false));

        WCLInterfaceType interfaceType = new WCLInterfaceType("DAO");
        interfaceType.addGenericType(entityName);
        interfaceType.addGenericType("Long");
        daoInterface.addImplementedInterface(interfaceType);

        generator.createFileFromInterface(daoInterface, configuration.getDaosSourcePath());
    }

    private void createDaoClass(List<String> arguments, WicketCoolConfiguration configuration) {

        String packageName = configuration.getPackageName();
        String daoName = arguments.get(1) + "DAOImpl";
        String entityName = arguments.get(1);

        System.out.println("Creating DAO class: " + daoName + ".java");

        WCLClass dao = generator.initClass(daoName, packageName + ".domain.dao");

        dao.addImplementedInterface(new WCLInterfaceType(entityName + "DAO"));

        WCLAnnotation annotation = new WCLAnnotation("Repository");
        annotation.addAttribute("value", new WCLStringValue(entityName.toLowerCase() + "DAO"));
        dao.addAnnotation(annotation);

        dao.addImport(new WCLImport("org.springframework.stereotype.Repository", false, false));
        dao.addImport(new WCLImport(packageName + ".domain.entities." + entityName, false, false));
        dao.addImport(new WCLImport("javax.persistence.EntityManager", false, false));
        dao.addImport(new WCLImport("javax.persistence.PersistenceContext", false, false));

        WCLClassType superClass = new WCLClassType("AbstractDAO");
        superClass.addGenericType(entityName);
        superClass.addGenericType("Long");
        dao.setSuperClass(superClass);

        WCLField entityManagerField = new WCLField("entityManager", new WCLNormalType("EntityManager"), WCLModifier.PRIVATE);
        entityManagerField.addAnnotation(new WCLAnnotation("PersistenceContext"));
        dao.addField(entityManagerField);

        WCLMethod getEMMethod = new WCLMethod("getEntityManager", new WCLNormalType("EntityManager"), WCLModifier.PUBLIC);
        getEMMethod.initMethodBody();
        getEMMethod.getBody().addStatement(new WCLReturnStatement(new WCLNormalValue("entityManager")));
        dao.addMethod(getEMMethod);

        WCLMethod getClazzMethod = new WCLMethod("getClazz", new WCLNormalType("Class<" + entityName + ">"), WCLModifier.PUBLIC);
        getClazzMethod.initMethodBody();
        getClazzMethod.getBody().addStatement(new WCLReturnStatement(new WCLClassValue(entityName)));
        dao.addMethod(getClazzMethod);


        generator.createFileFromClass(dao, configuration.getDaosSourcePath());

    }

    private void createDomainClass(List<String> arguments, WicketCoolConfiguration configuration) {

        String packageName = configuration.getPackageName();
        String entityName = arguments.get(1);

        System.out.println("Creating domain class: " + entityName + ".java");

        WCLClass entity = generator.initClass(entityName, packageName + ".domain.entities");
        WCLClassType abstractEntity = new WCLClassType("AbstractEntity");
        abstractEntity.addGenericType("Long");
        entity.setSuperClass(abstractEntity);

        entity.addImport(new WCLImport("javax.persistence", false, true));

        entity.addAnnotation(new WCLAnnotation(WCLAnnotation.ENTITY_NAME));
        WCLAnnotation tableAnnotation = new WCLAnnotation(WCLAnnotation.TABLE_NAME);
        tableAnnotation.addAttribute("name", new WCLStringValue(entityNameToPlural(entityName)));
        entity.addAnnotation(tableAnnotation);
        WCLAnnotation sequenceGeneratorAnnotation = new WCLAnnotation(WCLAnnotation.SEQUENCE_GENERATOR_NAME);
        sequenceGeneratorAnnotation.addAttribute("name", new WCLStringValue(entityName.toLowerCase() + "s_id_seq"));
        sequenceGeneratorAnnotation.addAttribute("sequenceName", new WCLStringValue(entityName.toLowerCase() + "s_id_seq"));
        entity.addAnnotation(sequenceGeneratorAnnotation);

        WCLField idField = new WCLField("id", new WCLNormalType("Long"), WCLModifier.PRIVATE);
        idField.addAnnotation(new WCLAnnotation("Id"));
        WCLAnnotation generatedAnnotation = new WCLAnnotation("GeneratedValue");
        idField.addAnnotation(generatedAnnotation);
        generatedAnnotation.addAttribute("generator", new WCLStringValue(entityNameToPlural(entityName) + "_id_seq"));
        generatedAnnotation.addAttribute("strategy", new WCLNormalValue("GenerationType.SEQUENCE"));
        entity.addField(idField);

        WCLMethod getIdMethod = new WCLMethod("getId", new WCLNormalType("Long"), WCLModifier.PUBLIC);
        getIdMethod.initMethodBody();
        getIdMethod.getBody().addStatement(new WCLReturnStatement(new WCLNormalValue("id")));
        entity.addMethod(getIdMethod);

        generator.createFileFromClass(entity, configuration.getEntitiesSourcePath());

    }

    private void createServiceInterface(List<String> arguments, WicketCoolConfiguration configuration) {
        String packageName = configuration.getPackageName();
        String serviceInterfaceName = arguments.get(1) + "Service";
        String entityName = arguments.get(1);

        System.out.println("Creating Service interface: " + serviceInterfaceName + ".java");

        WCLInterface daoInterface = generator.initInterface(serviceInterfaceName, packageName + ".service");

        generator.createFileFromInterface(daoInterface, configuration.getServicesSourcePath());
    }

    private String entityNameToPlural(String entityName) {
        return entityName.toLowerCase() + "s";
    }


    public String getDescription() {
        return "Creates domain specific objects (entity, dao)";
    }
}
